var util = require('util');
var events = require('events');
var fs = require('fs');
var config = require('jsonconfig');
var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database(config.DB, function() {
    db.run('PRAGMA foreign_keys=on');
	    }
);


// Make sure the file exists
// Load in the file
// uncompress the file if necessary
// check the header

// Does this host exist already?

// 	yes - get the id
//        look to see if we already have a checkpoint for this file
//  no  - create an entry in the hosts table and get the id

// for each zone
// does the zone exist already?

// yes - for each audit class
//       get the current data
//       for each datum
//       has the value changed?
//       yes - update the relevant audit_data field with an end date
//             add the new value with the new start date
//       no  - do nothing
// no  - for each audit class
//       get




// Load in the config file so we can know which versions of the s-audit
// client we support.

config.load(['config/config.json']);

// And here's the module

var ClientImport = function() {

	var group_name, // name of the group we're importing into (args[0])
		whole,		// whole imported file as raw JSON
		header,		// header chunk of imported file
		audit_plat,	// the host's platform type, for 'hosts' table
		audit_time,	// 'starttime' from the header
		audit_host, // 'hostname' from the header
		platform_id,
		audit_group // database ID field of audit group
		;

	// The functions in this class are chained together by events. When one
	// completes, it emits an event which is picked up, and starts the next
	// one. This guarantees the DB calls are done in the right order, and
	// all complete.

	events.EventEmitter.call(this);

	var that = this;

	// Public function 

	this.doImport = function(args) {

		// args[0] is the group
		// args[1] is file to read

		group_name = args[0];
		var audit_file = args[1];

		// We use foreign keys - make sure they're going to be enforced

		db.get('PRAGMA foreign_keys', function(err, res) {
			console.log('pragma res is ' + res.foreign_keys);
			that.emit('evBeginImport', audit_file);
		});

	}

	var _readFile = function(file) {

		// Read in the file and populate 'whole' and 'header' class
		// variables

		try {
			whole = JSON.parse(fs.readFileSync(file, 'utf8'));
			header = whole.header;
		}
		catch(e) {
			console.log("ERROR: cannot import JSON file '" + file + 
			"'. (Error: " + e.code + ")");
			process.exit(1);
		}

		this.emit('evFileRead');
	}

	var _processHeader = function() {
		
		// header is a class variable. In this method we get some more info
		// out of it and do a couple of checks.

		var date_chunk;	// temp var

		// Make sure the version of the file is supported
		
		if ( config.min_client_ver > header.sauditver ||
		config.max_client_ver < header.sauditver ) {
			throw('unsupported client version. (' + header.sauditver + ')');
		}

		// Make sure there's a hostname and a starttime

		if (header.hostname === undefined)
			throw('header does not contain a hostname value.');

		if (header.starttime === undefined)
			throw('header does not contain a starttime value.');

		// There ought to be a virtualization type to. If not, 'undefined'
		// will be fine

		if (whole.global.platform.virtualization !== undefined) {
			audit_plat = (whole.global.platform.virtualization);
		}

		// Get the audit time from the header. This is the value we use to
		// update the database, not the "audit complete" values in the audit
		// files. Unix date(1) thinks January is month 1, Javascript thinks
		// it's month 0.  This number goes in the 'checkpoints' table
		// 'timestamp' field later

		date_chunk = header.starttime.split(' ');

		audit_time = new Date(date_chunk[0], (date_chunk[1] - 1),
		date_chunk[2], date_chunk[3], date_chunk[4]).getTime();

		// We also need the hostname

		audit_host = header.hostname;

		this.emit('evHeaderParsed');
	}

	var _getAuditGroupID = function() {
	
		// Get the ID of the audit group we're using, or throw an error

		db.get('SELECT id FROM audit_groups WHERE name = ?', group_name,
		function(err, row) {

			if (err) {
				throw("unable to query 'audit_groups' table");
			}
			else if (row === undefined) {
				throw("group '" + group_name + "' does not exist.");
			}
			else {
				// Use an event to call the getHostID() function
				that.emit('evGIDRetrieved', row.id);
			}

		});

	}

	var _setAuditGroupID = function(audit_gid) {
		audit_group_id = audit_gid;
		this.emit('evSetAuditGroupID');
	}

	var _getPlatTypeID = function(plat_type) {
		
		// Get the platform type, or create a new one if it doesn't exist.
		// We use the audit_plat variable for this

		if (audit_plat) {
			db.get('SELECT id FROM plat_types WHERE type_name = ?',
			audit_plat, function(err, row) {

				if (err) {
					throw("unable to query 'plat_types' table");
				}
				else if (row === undefined) {
				
					db.run('INSERT INTO plat_types VALUES(?, ?)', [ null,
					audit_plat], function(err, res) {

						if (err) {
							throw('error updating plat_types table');
						}
						else {
							that.emit('evSetPlatTypeID', this.lastID);
						}

					});

				}
				else {
					that.emit('evSetPlatTypeID', row.id);
				}
			
			});

		}
		else {
			this.emit('evPlatTypeRetrieved');
		}

	}

	var _setPlatTypeID = function(plat_id) {
		platform_id = plat_id;
		this.emit('evPlatTypeRetrieved');
	}

	var _getHostID = function() {
		
		// If this host exists in the 'hosts' table, get its ID. If not, add
		// it by calling the _addHost method

		db.get('SELECT id FROM hosts WHERE audit_group = ? AND hostname = ?',
		[ audit_group_id, header.hostname ], function(err, row) { 

			var host_id;	// ID value from 'hosts' table

			if (err) {
				throw("unable to query 'hosts' table");
			}
			else if (row === undefined) {
				db.run('INSERT INTO hosts VALUES(?, ?, ?, ?)', [ null,
				audit_host, audit_group_id, platform_id], function(err, res)
				{
					that.emit('evHostExists', res.id);
				});
			}
			else {
				that.emit('evHostExists', row.id);
			}

		});

	}

	var _checkpoint = function(host_id) {
		
		// Insert the host ID and timestamp into the 'checkpoint' table. If
		// we already have this checkpoint, exit

		db.run('INSERT INTO checkpoints VALUES(?, ?)', [ host_id, audit_time
		], function(err, res) {

			if (err) {

				if (err.code === 'SQLITE_CONSTRAINT') {
					throw('this datafile has already been imported');
				}
				else {
					throw('unable to update checkpoint');
				}

			}
			else
				that.emit('evCheckpointed');

		});

	}


	var _processData = function() {
		console.log('processing');
	}

	var _progress = function(teats) {
		console.log('platform id is ' + platform_id);
	}
	
	this.on('evBeginImport', _readFile);
	this.on('evFileRead', _processHeader);
	this.on('evHeaderParsed', _getAuditGroupID);
	this.on('evGIDRetrieved', _setAuditGroupID);
	this.on('evSetAuditGroupID', _getPlatTypeID);
	this.on('evSetPlatTypeID', _setPlatTypeID);
	this.on('evPlatTypeRetrieved', _getHostID);
	this.on('evHostExists', _checkpoint);
	this.on('evCheckpointed', _processData);

}


/*

	importFile: function(args) {


		// We need the id of the group we've been given. If the group
		// doesn't exist, throw an exception


		// There's a table constraint on the 'checkpoints' table. If we've
		// seen this data before, throw an exception

		//console.log("INSERT INTO checkpoints VALUES(group_id" +  audit_time + ')');
		// If that fails, we already have this data

		//for (name in whole) {

			//if (whole.hasOwnProperty(name) && (name !== 'header')) {
//
				// Get the virtualization and remove anything in brackets
//
				//raw_virt = whole[name]['platform']['virtualization'];
//
				//short_virt = (raw_virt.match(/zone \(sparse/))
					//? 'sparse zone'
					//: raw_virt.replace(/\s+\(.*$/, '');
//
				//host_list[name] = short_virt;
			////}
		//	
		//}
//
		//console.log(host_list);
	}

}

	var get_host_id = function (err, row) {
			}
			else {
				audit_group_id = row.id;

				// Do we have this host already? If not, make it


			}
		}



*/

util.inherits(ClientImport, events.EventEmitter);
module.exports = new ClientImport();
